import React from 'react';
import ReactDOM from 'react-dom';
import { DraggableCore } from 'react-draggable';
import pick from 'lodash/pick';
import { isPx } from '../utils/is-object';

const validate = (value, limit = 10) => value < limit ? limit : value;
export default () => {
  return Comp => {
    return class Resizable extends React.Component {
      state = {
        x: undefined,
        y: undefined,
        width: undefined,
        height: undefined,
      };

      constructor(props) {
        super(props);
        this.ref = React.createRef();
      }

      componentDidMount() {
        if (this.ref.current) {
          const element = ReactDOM.findDOMNode(this.ref.current);
          // 内容实际宽高为 元素宽高减去padding
          this.initialWidth = element.clientWidth - 10;
          this.initialHeight = element.clientHeight - 10;
        }
      }

      onStop = () => {
        const { x, y, width, height } = this.state;
        const { node, editor } = this.props;
        let { style, position } = node;
        if (x) {
          position = position.set('x', x);
        }
        if (y) {
          position = position.set('y', y);
        }
        if (width) {
          style = style.set('width', width);
        }
        if (height) {
          style = style.set('height', height);
        }
        editor.updateNode(node, { style, position });
        this.setState({
          x: undefined,
          y: undefined,
          width: undefined,
          height: undefined,
        });
      };

      onStart = (event, data, direction) => {
        const { node } = this.props;
        const { width, height } = node.style;
        const initialState = {
          x: node.position && node.position.x,
          y: node.position && node.position.y,
          width: isPx(width) ? parseFloat(width, 10) : this.initialWidth,
          height: isPx(height) ? parseFloat(height, 10) : this.initialHeight,
        };
        const properties = {
          top: [ 'height', 'y' ],
          bottom: ['height'],
          left: [ 'width', 'x' ],
          right: ['width'],
          topLeft: [ 'height', 'width', 'x', 'y' ],
          topRight: [ 'height', 'width', 'y' ],
          bottomLeft: [ 'height', 'width', 'x' ],
          bottomRight: [ 'height', 'width' ],
        };
        this.setState({
          ...pick(initialState, properties[direction]),
        });
      };

      onResize = (event, data, direction) => {
        event.preventDefault();
        event.stopPropagation();
        switch (direction) {
          case 'top':
            this.setState(({ y, height }) => ({
              y: height <= 10 ? y : validate(y + data.deltaY),
              height: validate(height - data.deltaY),
            }));
            break;
          case 'bottom':
            this.setState(({ height }) => ({
              height: validate(height + data.deltaY),
            }));
            break;
          case 'left':
            this.setState(({ x, width }) => ({
              x: width <= 10 ? x : validate(x + data.deltaX),
              width: validate(width - data.deltaX),
            }));
            break;
          case 'right':
            this.setState(({ width }) => ({
              width: validate(width + data.deltaX),
            }));
            break;
          case 'topLeft':
            this.setState(({ x, y, width, height }) => ({
              x: validate(x + data.deltaX),
              width: validate(width - data.deltaX),
              y: validate(y + data.deltaY),
              height: validate(height - data.deltaY),
            }));
            break;
          case 'topRight':
            this.setState(({ y, width, height }) => ({
              width: validate(width + data.deltaX),
              y: validate(y + data.deltaY),
              height: validate(height - data.deltaY),
            }));
            break;
          case 'bottomRight':
            this.setState(({ width, height }) => ({
              width: validate(width + data.deltaX),
              height: validate(height + data.deltaY),
            }));
            break;
          case 'bottomLeft':
            this.setState(({ x, width, height }) => ({
              x: validate(x + data.deltaX),
              width: validate(width - data.deltaX),
              height: validate(height + data.deltaY),
            }));
            break;
          default:
            break;
        }
      };

      renderResizer = (
        direction = [
          // 'top',
          'bottom',
          // 'left',
          'right',
          // 'topLeft',
          // 'topRight',
          // 'bottomLeft',
          'bottomRight',
        ]
      ) => {
        const width = 8;
        const height = 8;
        const styles = {
          base: {
            position: 'absolute',
            border: '1px solid #3b97e3',
            width,
            height,
            backgroundColor: 'white',
          },
          top: {
            top: 0,
            left: 0,
            right: 0,
            cursor: 'ns-resize',
            margin: `-${height / 2}px auto`,
          },
          bottom: {
            bottom: 0,
            left: 0,
            right: 0,
            cursor: 'ns-resize',
            margin: `-${height / 2}px auto`,
          },
          left: {
            left: 0,
            top: 0,
            bottom: 0,
            cursor: 'w-resize',
            margin: `auto -${width / 2}px`,
          },
          right: {
            right: 0,
            top: 0,
            bottom: 0,
            cursor: 'e-resize',
            margin: `auto -${width / 2}px`,
          },
          topLeft: {
            top: -height / 2,
            left: -width / 2,
            cursor: 'nw-resize',
          },
          topRight: {
            top: -height / 2,
            right: -width / 2,
            cursor: 'ne-resize',
          },
          bottomLeft: {
            bottom: -height / 2,
            left: -width / 2,
            cursor: 'sw-resize',
          },
          bottomRight: {
            bottom: -height / 2,
            right: -width / 2,
            cursor: 'se-resize',
          },
        };
        if (Array.isArray(direction)) {
          return direction.map(this.renderResizer);
        }
        return (
          <DraggableCore
            onDrag={(event, data) => this.onResize(event, data, direction)}
            onStart={(event, data) => this.onStart(event, data, direction)}
            onStop={(event, data) => this.onStop(event, data, direction)}
            key={direction}
          >
            <div style={{ ...styles.base, ...styles[direction] }} />
          </DraggableCore>
        );
      };

      render() {
        const rect = this.state;
        return (
          <Comp
            ref={this.ref}
            {...this.props}
            rect={rect}
            renderResizer={this.renderResizer}
          />
        );
      }
    };
  };
};
